package com.ebupt.migu.music.siginIn.service.impl;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class AESUtil {

    private final static Base64.Encoder BASE64_ENCODER = Base64.getEncoder();
    private final static Base64.Decoder BASE64_DECODER = Base64.getDecoder();

    /**
     * 加密算法/加密模式/填充模式
     */
    private final static String CIPHER_MODE = "AES/CBC/PKCS5Padding";

    /**
     * 加密算法
     */
    private final static String ALGORITHM = "AES";

    /**
     * 加密
     *
     * @param content   待加密内容
     * @param secretKey 密钥
     * @return 加密内容
     */
    public static String encrypt(String content, String secretKey) throws Exception {
        SecretKeySpec secretKeySpec = new SecretKeySpec(getHexString(secretKey), ALGORITHM);
        Cipher cipher = Cipher.getInstance(CIPHER_MODE);
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, new IvParameterSpec(getHexString(secretKey)));
        byte[] encryptBytes = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8));
        return byte2hex(encryptBytes);
    }


    /**
     * 解密
     *
     * @param content   待解密内容
     * @param secretKey 密钥
     * @return 解密内容
     */
    public static String decrypt(String content, String secretKey) throws Exception {
        SecretKeySpec key = new SecretKeySpec(getHexString(secretKey), ALGORITHM);
        Cipher cipher = Cipher.getInstance(CIPHER_MODE);
        cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(getHexString(secretKey)));
        byte[] data = cipher.doFinal(hex2byte(content));
        return new String(data, StandardCharsets.UTF_8);
    }


    /**
     * 字节数组转成16进制字符串
     *
     * @param b 字节数组
     * @return
     */
    private static String byte2hex(byte[] b) {
        StringBuilder sb = new StringBuilder(b.length * 2);
        String tmp = "";
        for (int n = 0; n < b.length; n++) {
            // 整数转成十六进制表示
            tmp = (Integer.toHexString(b[n] & 0XFF));
            if (tmp.length() == 1) {
                sb.append("0");
            }
            sb.append(tmp);
        }
        return sb.toString().toUpperCase();
    }

    /**
     * 16进制字符串转成字节数组
     *
     * @param hexStr 16进制字符串
     * @return
     */
    private static byte[] hex2byte(String hexStr) {
        if (hexStr == null || hexStr.length() < 2) {
            return new byte[0];
        }
        hexStr = hexStr.toLowerCase();
        int l = hexStr.length() / 2;
        byte[] result = new byte[l];
        for (int i = 0; i < l; ++i) {
            String tmp = hexStr.substring(2 * i, 2 * i + 2);
            result[i] = (byte) (Integer.parseInt(tmp, 16) & 0xFF);
        }
        return result;
    }


    /**
     * 获取16位字符串的字节数组
     *
     * @param str 待转换16字符串
     * @return
     */
    private static byte[] getHexString(String str) {
        if (str == null) {
            str = "";
        }
        StringBuilder sb = new StringBuilder(16);
        sb.append(str);
        while (sb.length() < 16) {
            sb.append("0");
        }
        if (sb.length() > 16) {
            sb.setLength(16);
        }
        return sb.toString().getBytes(StandardCharsets.UTF_8);
    }

    /**
     * base64加密
     *
     * @param content
     * @return
     */
    public static String base64Encrypt(String content) {
        return BASE64_ENCODER.encodeToString(content.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * base64解密
     *
     * @param content
     * @return
     */
    public static String base64Decrypt(String content) {
        byte[] bytes = BASE64_DECODER.decode(content);
        return new String(bytes, StandardCharsets.UTF_8);
    }

    public static void main(String[] args) throws Exception {
        // AES-128-CBC密钥
        String aesSecretKey = "fs3wgOUwxF8oEPqr";
        String content = "Migu#2020";
        // base64加密
        String base64EncryptStr = base64Encrypt(aesSecretKey);
        String base64DecryptStr = base64Decrypt(base64EncryptStr);
        System.out.println("base64加密结果：" + base64EncryptStr + ", base64解密结果：" + base64DecryptStr);
        // aes-128-cbc加密
        String encrypt = encrypt(content, base64DecryptStr);
        String decrypt = decrypt(encrypt, base64DecryptStr);
        System.out.println("aes加密结果：" + encrypt + ", aes解密结果：" + decrypt);
    }
}